using System;
using System.Text;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Web;

using Framework;

namespace SchemaMonitor
{
    //Collection Class (Customisable half)
    public partial class CMetaTagList
    {
		#region Filters
		public CMetaTagList OneToMany
		{
			get
			{
				return CTagType.Cache.OneToMany.Tags;
			}
		}
		private List<string> _names;
		public List<string> Names
		{
			get
			{
				if (null == _names || _names.Count != this.Count)
				{
					var temp = new List<string>(this.Count);
					foreach (var i in this)
						temp.Add(i.TagName);
					_names = temp;
				}
				return _names;
			}
		}


		private CTagType FB_Filters { get { return CTagType.Cache.FB_Filters; } }

		public CMetaTag Delete { get { return GetOrCreate("ToDelete", FB_Filters.TypeId); } }
		public CMetaTag XRated { get { return GetOrCreate("XRated", FB_Filters.TypeId); } }
		public CMetaTag Laptop { get { return GetOrCreate("Laptop", FB_Filters.TypeId); } }

		private CTagType PostRating { get { return CTagType.Cache.FB_PostRating; } }
		public CMetaTag Feat { get { return GetOrCreate("Featured", PostRating.TypeId); } }
		public CMetaTag High { get { return GetOrCreate("High", PostRating.TypeId); } }
		public CMetaTag Med { get { return GetOrCreate("Med", PostRating.TypeId); } }
		public CMetaTag Low { get { return GetOrCreate("Low", PostRating.TypeId); } }
		public CMetaTag Crim { get { return GetOrCreate("Crim", PostRating.TypeId); } }


		public bool Has(int tagId) { return null != GetById(tagId); }
		public CMetaTag GetOrCreate(string name, int typeId)
		{
			foreach (var i in this.GetByTypeId(typeId))
				if (i.TagName.ToLower() == name.ToLower())
					return i;
			var a = new CMetaTag();
			a.TagTypeId = typeId;
			a.TagName = name;
			a.Save();
			return a;
		}
		#endregion

		#region Aggregation
		#endregion

		#region Searching (Optional)
		//Represents a simple search box to search PK and any string columns (add overloads as required, based on the pattern below)
		//e.g. public CMetaTagList Search(string nameOrId, int typeId, int parentTagId) { ...
		public CMetaTagList Search(string nameOrId)
        {
            //1. Normalisation
            nameOrId = (nameOrId??string.Empty).Trim().ToLower();
            
            //2. Start with a complete list
            CMetaTagList results = this;
            
            //3. Use any available index, such as those generated for fk/bool columns
            //Normal Case - non-unique index (e.g. foreign key)
            //if (int.MinValue != typeId) results = results.GetByTypeId(typeId);
            //if (int.MinValue != parentTagId) results = results.GetByParentTagId(parentTagId);

            //Special case - unique index (e.g. primary key)
            /*
            if (!string.IsNullOrEmpty(nameOrId)) 
            {
                int id;
                if (int.TryParse(nameOrId, out id))
                {
                    CMetaTag obj = this.GetById(id);
                    if (null != obj)
                    {
                        results = new CMetaTagList(1);
                        results.Add(obj);
                        return results;
                    }
                }
            }
            */
            
            //4. Exit early if remaining (non-index) filters are blank
            if (string.IsNullOrEmpty(nameOrId)) return results; 
            
            //5. Manually search each record using custom match logic, building a shortlist
            CMetaTagList shortList = new CMetaTagList();
            foreach (CMetaTag i in results)
                if (Match(nameOrId, i))
                    shortList.Add(i); 
            return shortList;
        }
        //Manual Searching e.g for string-based columns i.e. anything not indexed (add more params if required)
        private bool Match(string name, CMetaTag obj)
        {
            if (!string.IsNullOrEmpty(name)) //Match any string column
            {
                if (null != obj.TagName && obj.TagName.ToLower().Contains(name))   return true;
                return false;   //If filter is active, reject any items that dont match
            }
            return true;    //No active filters (should catch this in step #4)
        }
        #endregion

        #region Cloning
        public CMetaTagList Clone(CDataSrc target) //, int parentId)
        {
            //No Transaction
            if (target is CDataSrcRemote)
                return Clone(target, null); //, parentId);

            //Transaction
            using (IDbConnection cn = target.Local.Connection())
            {
                IDbTransaction tx = cn.BeginTransaction();
                try
                {
                    CMetaTagList clone = Clone(target, tx); //, parentId);
                    tx.Commit();
                    return clone;
                }
                catch
                {
                    tx.Rollback();
                    throw;
                }
            }
        }
        public CMetaTagList Clone(CDataSrc target, IDbTransaction txOrNull) //, int parentId)
        {
            CMetaTagList list = new CMetaTagList(this.Count);
            foreach (CMetaTag i in this)
                list.Add(i.Clone(target, txOrNull)); //, parentId));  *Child entities must reference the new parent
            return list;
        }
		#endregion




		public new void Add(CMetaTag item)
		{
			if (null != _index && !_index.ContainsKey(item.TagId))
				_index[item.TagId] = item;
			_indexByParentTagId = null;
			_indexByTypeId = null;
			base.Add(item);
		}
		public new void Remove(CMetaTag item)
		{
			if (null != _index && _index.ContainsKey(item.TagId))
				_index.Remove(item.TagId);
			_indexByParentTagId = null;
			_indexByTypeId = null;
			base.Remove(item);
		}
	}
}
